package com.zdsoft.site;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.regex.Pattern;

import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.apache.poi.xwpf.usermodel.XWPFRun;
import org.apache.poi.xwpf.usermodel.XWPFTable;
import org.apache.poi.xwpf.usermodel.XWPFTableCell;
import org.apache.poi.xwpf.usermodel.XWPFTableRow;
import org.artofsolving.jodconverter.OfficeDocumentConverter;
import org.artofsolving.jodconverter.office.DefaultOfficeManagerConfiguration;
import org.artofsolving.jodconverter.office.OfficeManager;
import org.beetl.core.Configuration;
import org.beetl.core.GroupTemplate;
import org.beetl.core.resource.StringTemplateResourceLoader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;

import com.zdsoft.rock.common.AppException;
import com.zdsoft.rock.common.util.StringUtil;

/**
 * 这是一个工具类，主要是为了使Office2003-2007全部格式的文档
 * (.doc|.docx|.xls|.xlsx|.ppt|.pptx)转化为pdf文件
 */
public class OfficeToPDF {
	private static Logger logger=LoggerFactory.getLogger(OfficeToPDF.class);
	private static OfficeManager officeManager = null;
	
	private static Configuration cfg=null; //模板配置
	private static GroupTemplate gt=null;  //穿件模板
	static {
		try {
			if(cfg==null) cfg = Configuration.defaultConfiguration();	
			if(gt==null) gt= new GroupTemplate(new StringTemplateResourceLoader(), cfg);		
		} catch (Exception e) {
			throw new AppException("1000","beetl模板引擎初始化失败");
		}
	}
	private OfficeToPDF() {
	}
	/**
	 * 获取OpenOffice.org 3的安装目录
	 * 可以定义一个全局的环境变量officeHome来指定openoffice安装的路径
	 * 如果没有指定环境变量则根据windows和linux取默认安装位置
	 */
	private static String getOfficeHome() {
		String osName = System.getProperty("os.name");
		String officeHome = System.getenv("officeHome");// 获取环境变量
		if (Pattern.matches("Linux.*", osName)) {
			return officeHome != null ? officeHome : "/opt/openoffice.org3";
		} else if (Pattern.matches("Windows.*", osName)) {
			return officeHome != null ? officeHome : "C:\\Program Files (x86)\\OpenOffice.org 3";
		}
		return null;
	}
	/**
	 * office模板文件填充参数之后转换为pdf文件<br/>
	 * 基本流程为:office模板文件-->替换变量之后(临时文件)-->转化为pdf文件<br/>
	 * @param inputFilePath   模板文件全路径
	 * @param outputFilePath  模板文件输出的pdf文件全路径
	 * @param param 替换模板文件中的参数
	 */
	public static void officeTemplate2pdf(String inputFilePath, String outputFilePath,Map<String, Object> param){
		try {
			//输出文件为空则用输入文件名代替后缀变为pdf
			if(!StringUtils.hasLength(outputFilePath)){
				String fileNameExt=StringUtils.getFilenameExtension(inputFilePath);
				outputFilePath = inputFilePath.replaceAll("." + fileNameExt, ".pdf");	
			}
			//1.填充office模板文件
			logger.debug("模板文件变量替换开始:template={}",inputFilePath);
			XWPFDocument doc=generateWord2(inputFilePath,param);
			logger.debug("模板文件变量替换完成:template={}",inputFilePath);
			//生成临时文件
			if(doc==null){
				logger.error("模板文件替换变量异常无法得到正常的对象");
				return;
			}
			String tempFileName=StringUtil.generateRandomGUID32()+"."+StringUtils.getFilenameExtension(inputFilePath);
			FileOutputStream outputStream=new FileOutputStream(tempFileName);
			doc.write(outputStream);
			outputStream.close();
			logger.debug("生成临时文件成功:{}",tempFileName);
			//2.把填充之后临时文件转换为的office文件转换为pdf格式的文件
			office2pdf(tempFileName,outputFilePath);
			logger.debug("临时文件转换为pdf文件成功.{}",outputFilePath);
			//删除临时文件
			File file=new File(tempFileName);
			if(file.exists()) file.delete();
			logger.debug("删除合同临时文件成功.{}",tempFileName);		
		} catch (Exception e) {
			logger.error("模板文件填充转换为pdf出错",e);
		}
	}
	/**
	 * Office2003-2007全部格式的文档(.doc|.docx|.xls|.xlsx|.ppt|.pptx) 转化为pdf文件
	 * @param inputFilePath  源文件路径，如："e:/test.docx"
	 * @param outputFilePath 目标文件路径，如："e:/test_docx.pdf"
	 * @return
	 */
	public static void office2pdf(String inputFilePath, String outputFilePath) {
		if(!StringUtils.hasLength(inputFilePath)){
			logger.debug("输入文件名不符合规范:{}",inputFilePath);
		}
		File inputFile = new File(inputFilePath);
		//输入文件存在
		if(inputFile.exists()){
			//输出文件为空则用输入文件名代替后缀变为pdf
			if(!StringUtils.hasLength(outputFilePath)){
				String fileNameExt=StringUtils.getFilenameExtension(inputFilePath);
				outputFilePath = inputFilePath.replaceAll("." + fileNameExt, ".pdf");	
			}
			File outputFile=new File(outputFilePath);
			// 假如目标路径不存在,则新建该路径
			if (!outputFile.getParentFile().exists()) {
				outputFile.getParentFile().mkdirs();
			}
			startOffice();
			OfficeDocumentConverter converter = new OfficeDocumentConverter(officeManager);
			converter.convert(inputFile, outputFile);
			stopOffice();
		}
	}
	/**
	 * 启动office服务
	 */
	public static void startOffice() {
		DefaultOfficeManagerConfiguration configuration = new DefaultOfficeManagerConfiguration();
		try {
			logger.debug("准备启动服务....OfficeHome={}",getOfficeHome());
			configuration.setOfficeHome(getOfficeHome());// 设置OpenOffice.org安装目录
			configuration.setPortNumbers(8100); // 设置转换端口，默认为8100
			configuration.setTaskExecutionTimeout(1000 * 60 * 5L);// 设置任务执行超时为5分钟
			configuration.setTaskQueueTimeout(1000 * 60 * 60 * 24L);// 设置任务队列超时为24小时

			officeManager = configuration.buildOfficeManager();
			officeManager.start(); // 启动服务
			logger.debug("office转换服务启动成功!");
		} catch (Exception ce) {
			logger.debug("office转换服务启动失败!详细信息:" + ce);
		}
	}
	/**
	 * 关闭office服务器
	 */
	public static void stopOffice() {
		logger.debug("关闭office转换服务....");
		if (officeManager != null) {
			officeManager.stop();
		}
		logger.debug("关闭office转换成功!");
	}
	/**
	 * 替换模板文件中的所有变量为实际值
	 * 变量要求为:${memberCd},遵循beetl模板引擎规范
	 * @param inputFilePath 模板文件的全路径
	 * @param param
	 * @return
	 */
	public static XWPFDocument generateWord(String inputFilePath,Map<String, Object> param) {
		try {
			if(StringUtils.isEmpty(inputFilePath)) throw new AppException("1001","模板文件名不能为空");
			
			if(!new File(inputFilePath).exists())  throw new AppException("1001","模板文件不存在");
			
			if(param==null || param.size()<0)      throw new AppException("1001","没有指定要替换的变量值");
			
			//OPCPackage pack = POIXMLDocument.openPackage(inputFilePath);
			//XWPFDocument doc=new XWPFDocument(pack);
			XWPFDocument doc = new XWPFDocument(new FileInputStream(inputFilePath)); 
			List<XWPFRun> runs=new ArrayList<XWPFRun>();
			//1.查找所有段落
			List<XWPFParagraph> parags=doc.getParagraphs();
			for (XWPFParagraph p : parags) {
				if(!StringUtils.isEmpty(p.getText())){
					runs.addAll(p.getRuns());
				}
			}
			logger.debug("模板文件中的段落数:{}",parags.size());
			//查找所有表格
			List<XWPFTable> tables=doc.getTables();
			logger.debug("模板文件中的表格数:{}",tables.size());
			for (XWPFTable table : tables) {
				List<XWPFTableRow> rows=table.getRows();
				for (XWPFTableRow row : rows) {
					List<XWPFTableCell> cells=row.getTableCells();
					for (XWPFTableCell cell : cells) {
						for (XWPFParagraph p : cell.getParagraphs()) {
							if(!StringUtils.isEmpty(p.getText())){
								runs.addAll(p.getRuns());
							}
						}
					}
				}
			}
			logger.debug("替换模板中的所有的变量:{}",param);
			for (XWPFRun r : runs) {
				if(!StringUtils.isEmpty(r.getText(0))){
					if(r.getText(0).contains("$")||r.getText(0).contains("{")){
						logger.debug("{}",r.getText(0));
						org.beetl.core.Template t = gt.getTemplate(r.getText(0));
						t.binding(param);//绑定参数
						r.setText(t.render(),0);//渲染模板赋值
					}
				}
			}	
			return doc;
		} catch (Exception e) {
			logger.error("",e);
			throw new AppException("1000","模板替换错误");
		}
	}
	/**
	 * 用指定的参数填充office模板文件,参数直接就是变量名称，容易出现混淆不建议采用
	 * @param officeTemplate
	 * @param params
	 * @return
	 */
	@Deprecated
	public static XWPFDocument generateWord2(String officeTemplate,Map<String, Object> params) {  
        try {
        	if(params==null||params.size()<=0) throw new AppException("1000","必须制定要替换的参数");
        	if(!new File(officeTemplate).exists()){
        		throw new AppException("1001","模板文件不存在:"+officeTemplate);
        	}
            //OPCPackage pack = POIXMLDocument.openPackage(officeTemplate);  
            //XWPFDocument doc = new XWPFDocument(pack);
            XWPFDocument doc = new XWPFDocument(new FileInputStream(officeTemplate));  
                //处理段落  
            logger.debug("替换模板文件中的变量:{}",params);
            List<XWPFParagraph> paragraphList = doc.getParagraphs();  
            processParagraphs(paragraphList, params, doc);
            logger.debug("模板文件处理完毕.段落数:{}",paragraphList.size());
            //处理表格  
            Iterator<XWPFTable> it = doc.getTablesIterator();
            while (it.hasNext()) {  
                XWPFTable table = it.next();  
                List<XWPFTableRow> rows = table.getRows();  
                for (XWPFTableRow row : rows) {  
                    List<XWPFTableCell> cells = row.getTableCells();  
                    for (XWPFTableCell cell : cells) {  
                        List<XWPFParagraph> paragraphListTable =  cell.getParagraphs();  
                        processParagraphs(paragraphListTable, params, doc);  
                    }  
                }
            }
            logger.debug("模板文件表格处理完毕.表格数:{}",doc.getTables().size());
            return doc;
        } catch (Exception e) {  
            logger.error("模板替换出错",e);
            throw new AppException("1002","模板替换异常");
        }  
    } 
    /** 
     * 处理段落 
     * @param paragraphList 
     */  
	@Deprecated
    private static void processParagraphs(List<XWPFParagraph> paragraphList,Map<String, Object> param,XWPFDocument doc){  
        if(paragraphList != null && paragraphList.size() > 0){  
        	List<XWPFRun> runs;
        	XWPFRun run;
        	for(XWPFParagraph paragraph:paragraphList){  
                runs = paragraph.getRuns();
                for (int i=0;i<runs.size();i++) { 
                	run=runs.get(i);
                    String text = run.toString(); 
                    if(text != null){  
                        for (Entry<String, Object> entry : param.entrySet()) {  
                            String key = entry.getKey(); 
                            if(text.indexOf(key) != -1){  
                            	Object value=entry.getValue();
                            	String newValue = "";//代替值为null报错的情况
                            	if(value==null){
                            		value="";
                            	}
                            	newValue = value+"";
                                text = text.replaceAll(key,newValue); 
                                run.setText(text,0);
                                //paragraph.removeRun(i);
                                //paragraph.insertNewRun(i).setText(text);
                            }  
                        }  
                    }  
                }  
            }  
        }  
    }	
	public StringBuffer toHtmlString(String docFile, String htmlfile) {
		// 转换word文档为网页文件
		office2pdf(docFile, htmlfile);
		// 获取html文件流
		StringBuffer htmlSb = new StringBuffer();
		try {
			BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(htmlfile)));
			while (br.ready()) {
				htmlSb.append(br.readLine());
			}
			br.close();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		// 返回经过清洁的html文本
		return htmlSb;
	}
	
}
